#ifndef __DiffMuscle3_h__
#define __DiffMuscle3_h__

#include <OpenSim/OpenSim.h>
#include <OpenSim/Simulation/Model/Muscle.h>
#include "osimPluginDLL.h"
#include <OpenSim/Actuators/Millard2012EquilibriumMuscle.h>

#ifdef SWIG
    #ifdef OSIMACTUATORS_API
        #undef OSIMACTUATORS_API
        #define OSIMACTUATORS_API
    #endif
#endif

namespace OpenSim {

class OSIMPLUGIN_API DiffMuscle3 :
	public Millard2012EquilibriumMuscle
{
public:
	
	struct MuscleDynamicsInfoFast : public MuscleDynamicsInfo
	{	
		double activationFast;
	};

	OpenSim_DECLARE_CONCRETE_OBJECT( DiffMuscle3, Millard2012EquilibriumMuscle);

	OpenSim_DECLARE_PROPERTY(maxContractionVelocityFast, double,
		"Maximum contraction velocity of the fibers, in optimal fiberlengths/second");

	OpenSim_DECLARE_PROPERTY( default_activation_fast, double,
                       "assumed initial activation level of fast fiber if none is assigned.");

	OpenSim_DECLARE_PROPERTY( activationModelFast, MuscleFirstOrderActivationDynamicModel, "activation model for fast fiber" );
	OpenSim_DECLARE_PROPERTY( activationModel2ndOrderFast, MuscleSecondOrderActivationDynamicModel, "2nd order activation dynamics model with a lower bound");
	
	OpenSim_DECLARE_PROPERTY( scaleFactorFast, double, "scale factor for fast fiber" );
	OpenSim_DECLARE_PROPERTY( scaleFactorSlow, double, "scale factor for slow fiber" );
	
public:
	DiffMuscle3();

	DiffMuscle3( const std::string &aName,
                 double aMaxIsometricForce,
                 double aOptimalFiberLength,
				 double aTendonSlackLength,
                 double aPennationAngle );
	
	
   /*
    @returns the default activation level that is used as an initial condition
             if none is provided by the user.
    */

    double getDefaultActivationFast() const;

	/**
   @returns the MuscleFirstOrderActivationDynamicModel 
            that this muscle model uses
   */
	const MuscleFirstOrderActivationDynamicModel& 
        getActivationModelFast() const;

    const MuscleSecondOrderActivationDynamicModel& 
       getSecondOrderActivationModelFast() const;


	double getScaleFactorFast() const;
	double getScaleFactorSlow() const;
	
	/* Set the activationModel for fast fiber */

	void setActivationModelFast( MuscleFirstOrderActivationDynamicModel& aActivationMdl );
	void setSecondOrderActivationModelFast( MuscleSecondOrderActivationDynamicModel& aActivationMdlFast );


	void setScaleFactorFast( double scf );
	void setScaleFactorSlow( double scs );

/* set and get state variables */

	 /**
    @param s The state of the system
    @param order the desired derivative order
    @returns the time derivative of activation
    */
    double getActivationDerivativeFast(const SimTK::State& s,int order) const;

	double calcActivationDerivativeFast(const SimTK::State& s, int order) const;

	void setMaxContractionVelocityFast( double maxContractionVelocityFast ) ;
	double getMaxContractionVelocityFast() const;

	double getActivationFast(const SimTK::State& s) const;

	/**
    @param activation the default activation level that is used to initialize
           the muscle
    */
    void setDefaultActivationFast(double activation);
	

	void setActivationFast(SimTK::State& s, double activation) const;
	
	 /**
    @returns A string arraw of the state variable names
    */
    //Array<std::string> getStateVariableNames() const ;

    /**
    @param stateVariableName the name of the state varaible in question
    @returns The system index of the state variable in question
    */
    //SimTK::SystemYIndex getStateVariableSystemIndex(const std::string &stateVariableName) const ;
	
	double getMinimumActivationFast() const;

	const MuscleDynamicsInfo& getMuscleDynamicsInfo(const SimTK::State& s) const;
	
	MuscleDynamicsInfo& updMuscleDynamicsInfo(const SimTK::State& s) const;

	/* compute actuation */
	
	double computeActuation( const SimTK::State& s ) const;

	void computeInitialFiberEquilibrium(SimTK::State& s) const;
 

protected:
    /** Calculate activation rate */
    double calcActivationRateFast(const SimTK::State& s) const; 
	double calcActiveFiberForceAlongTendonFast(double activation, 
                                            double fiberLength, 
                                            double fiberVelocity) const;
public:
	void initStateFromProperties(SimTK::State& s) const;
    
    /**Sets the default state for ModelComponent*/
    void setPropertiesFromState(const SimTK::State& s);
	
    /**computes state variable derivatives*/
    SimTK::Vector computeStateVariableDerivatives(
        const SimTK::State& s) const;
	
	//void connectToModel(Model& model);

	void addToSystem( SimTK::MultibodySystem& system ) const;
	void connectToModel(Model& model);

    /** calculate muscle's active and passive force-length, force-velocity, 
        tendon force, relationships and their related values */
    virtual void  calcMuscleDynamicsInfo(const SimTK::State& s, 
                                    MuscleDynamicsInfo& mdi) const;

	void  calcFiberVelocityInfoFast(const SimTK::State& s, 
                                FiberVelocityInfo& fvi) const ;

private:
    //The name used to access the activation state
	static const std::string STATE_ACTIVATION_FAST_NAME;
	static const std::string STATE_ACTIVATION_DERIVATIVE_FAST_NAME;

    void setNull();
    void constructProperties();
    
    /*Builds all of the components that are necessary to use this 
    muscle model in simulation*/
    void buildMuscle() ;

	void ensureMuscleUpToDate() ;


	SimTK::Vector initMuscleState( SimTK::State& s, double aActivation, double aActivationFast,
                             double aSolTolerance, int aMaxIterations) const;
 
    
	
	SimTK::Vector estimateMuscleFiberState(double aActivation, double aActivationFast,
                    double pathLength, double pathLengtheningSpeed, 
                    double aSolTolerance, int aMaxIterations) const;
	


};	// END of class DiffMuscle
//=============================================================================
} // end of namespace OpenSim

#endif //__DiffMuscle3_h__